/*
 * Created by Spear (http://www.codernet.es), spear@codernet.es
 * Coordinator of XNA Community (http://www.codeplex.com/XNACommunity)
 * 
 */

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Content.Pipeline;

namespace XMasContent
{
    public class CCal3DMeshParser
    {
        public struct TSubMesh
        {
            public int material_id;
            public int vertexCount;
            public int faceCount;
            public int lodCount;
            public int springCount;
            public int textureCoordinateCount;
        };

	    // A vertex in the file and associated structs
        public struct TCalVertex
        {
	        public Vector3 position;
	        public Vector3 normal;
            public Vector2 tex_coord;
            public TInfluence[] influences;
	    };

        public struct TInfluence
        {
            public int boneId;
            public float weight;
        };

        public struct TPhysicalProperty
        {
            public float weight;
        };

        public struct TSpring
        {
            public int id0, id1;
            public float springCoefficient;
            public float idleLength;
        };
        public List<TCalVertex> vertices = new List<TCalVertex>();
        public int[] indices;
        
    
        bool isValid(char[] magic)
        {
			return ( magic[ 0 ] == 'C' && magic[ 1 ] == 'M' && magic[ 2 ] == 'F' && magic[ 3 ] == 0x00 ) ;
		}

        void loadSubMesh(BinaryReader reader)
        {
            TSubMesh sub_mesh = new TSubMesh();
            sub_mesh.material_id = reader.ReadInt32();
            sub_mesh.vertexCount = reader.ReadInt32();
            sub_mesh.faceCount = reader.ReadInt32();
            sub_mesh.lodCount = reader.ReadInt32();
            sub_mesh.springCount = reader.ReadInt32();
            sub_mesh.textureCoordinateCount = reader.ReadInt32();


	        // AABB
	        Vector3 min_point = Vector3.Zero;
            Vector3 max_point = Vector3.Zero;
            XmasContent.GetInstance().warn("Loading " + sub_mesh.vertexCount + " vtxs of cmf... Will take some time...\n", false);

            int indices_offset = vertices.Count;

            for (int i = 0; i < sub_mesh.vertexCount; ++i)
            {
                TCalVertex cal_vertex = new TCalVertex();
                cal_vertex.position = XmasContent.GetInstance().readVector3(reader);
                cal_vertex.normal = XmasContent.GetInstance().readVector3(reader);
	            reader.ReadInt32();
	            reader.ReadInt32();
                // AABB
                if (i == 0)
                {
                    max_point = cal_vertex.position;
                    min_point = cal_vertex.position;
                }
                else
                {
                    if (cal_vertex.position.X > max_point.X)
                        max_point.X = cal_vertex.position.X;
                    if (cal_vertex.position.X < min_point.X)
                        min_point.X = cal_vertex.position.X;
                    if (cal_vertex.position.Y > max_point.Y)
                        max_point.Y = cal_vertex.position.Y;
                    if (cal_vertex.position.Y < min_point.Y)
                        min_point.Y = cal_vertex.position.Y;
                    if (cal_vertex.position.Z > max_point.Z)
                        max_point.Z = cal_vertex.position.Z;
                    if (cal_vertex.position.Z < min_point.Z)
                        min_point.Z = cal_vertex.position.Z;
                }

                //Texture Coordinates
		        for( int j=0; j<sub_mesh.textureCoordinateCount; ++j ) 
                {
                    Vector2 tex_coord = XmasContent.GetInstance().readVector2(reader);
			        if( j == 0 )
                        cal_vertex.tex_coord.X = tex_coord.X;
                    cal_vertex.tex_coord.Y = tex_coord.Y;
		        }

                int influenceCount = reader.ReadInt32();
                //SDK_ASSERT(influenceCount <= 4 || !"A max of 4 influences per vertex are supported");
                cal_vertex.influences = new TInfluence[influenceCount];

		        for(int j=0; j<influenceCount; ++j ) 
                {
                    cal_vertex.influences[j].boneId = reader.ReadInt32();
                    cal_vertex.influences[j].weight = reader.ReadSingle();
		        }

                if (sub_mesh.springCount > 0) //TPhysicalProperty
                    reader.ReadSingle();

                vertices.Add(cal_vertex);
            }

            for (int i = 0; i < sub_mesh.springCount; ++i)
            { // TSpring
                reader.ReadInt32();
                reader.ReadInt32();
                reader.ReadSingle();
                reader.ReadSingle();
	        }

	        // Read the faces
            int idx = 0;
            if (indices != null && indices.Length > 0)
                idx = indices.Length;

            Array.Resize<int>(ref indices, idx + (sub_mesh.faceCount * 3) );
            for (int i = 0; i < sub_mesh.faceCount; ++i)
            {
                indices[idx + 2] = indices_offset + reader.ReadInt32();
                indices[idx + 1] = indices_offset + reader.ReadInt32();
                indices[idx + 0] = indices_offset + reader.ReadInt32();
                idx += 3;
	        } 
        }

        public void load(string filename, ContentImporterContext context)
        {
            //System.Diagnostics.Debugger.Launch(); 
            XmasContent.GetInstance().SetContextImporter(context);
            FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read);
            BinaryReader reader = new BinaryReader(file);
            char[] magic = new char[4];
            magic = reader.ReadChars(4);
            if (isValid(magic))
            {
                reader.ReadInt32();
                int submesh_count = reader.ReadInt32();
                for (int i = 0; i < submesh_count; ++i)
                {
                    loadSubMesh(reader);
                }
            }
            else
            {
                throw new ArgumentNullException("File: " + filename + ", CMF Version not supported.\n");
            }
            reader.Close();
        }
    }
}
